/*****************************************************************//**
 * \file   CDBReader.cpp
 * \brief  CDBReader
 * 
 * \author Wyatt
 * \date   May 2023
 *********************************************************************/
#pragma once
#include "CDBReader.h"
#include "Includes.h"
#include "Headers.h"

#include <Python.h>
#include <iostream>
#include <fstream>
#include <sstream>
#include "ReadMesh.h"


#include <vtkNew.h>
#include <vtkPoints.h>
#include <vtkSmartPointer.h>
#include <vtkCellArray.h>
#include <vtkUnstructuredGrid.h>
#include <vtkXMLUnstructuredGridWriter.h>
#include <vtkHexahedron.h>

using namespace std;
bool CDBReader::AnalysisDimention3D = true;

wchar_t* char_to_wchar(const char* str) {
	size_t len = mbstowcs(nullptr, str, 0) + 1; // 计算所需缓冲区大小
	wchar_t* wstr = new wchar_t[len];
	mbstowcs(wstr, str, len);
	return wstr;
}

CDBReader::CDBReader()
{

	_curStep = -1;
	_curInitialTemperature = 273.15;
}

CDBReader::~CDBReader(void)
{
	//std::cerr << "~CDBReader" << std::endl;
	/*if (_file->is_open())
		_file->close();*/
	cleanUp();
}

CDBReader* CDBReader::_instance = nullptr;

CDBReader* CDBReader::Inst()
{
	if (!_instance)
		_instance = new CDBReader();
	return _instance;
	/*static CDBReader  inst;
	return &inst;*/
}

void CDBReader::init(string filePath)
{
	//cleanUp();
	if (_file)
	{
		delete _file;
	}
	_file = new TxtMemStream(filePath);
	//std::cerr << "_file: " << _file << std::endl;
	//std::cerr << "filepath: " << filePath<<std::endl;
	//std::cerr << "__filepath: " << _filePath<<std::endl;
	if (!_filePath.empty()) { _filePath.clear(); }
	_filePath = filePath;
	if (!_file->is_open()) {}
		//FDEBUG("Error: open cdb file error");
	//std::cerr << "__filepath: " << _filePath << std::endl;
}

void CDBReader::cleanUp()
{
	/*for (auto& it : _etVec)
		delete it;
	for (auto& it : _nodeMap)
		delete it.second;*/
	//undefined behavior for struct MaterialBase
	/*for (auto& it : _matMap) {
		for (auto& itSub : it.second) delete itSub;
	}*/
	SAFE_DEL(_file);
	_curMPTEMP.clear();
	_curTB.mid = 0;
	_curTB.TType = ANSYS_TB_CNT;
	_curTB.DataCnt = 0;
	
	_filePath.clear();
	_nLine = 0;
	_variables.clear();
	_dimMap.clear();
	_vecRealSet.clear();
	_etVec.clear();
	_etMap.clear();
	_nodeMap.clear();
	_propMap.clear();
	_nodeHlp.clear();
	_elementOut.clear();
	_elemAnsysIdToOutid.clear();
	//_matMap.clear();
	_secMap.clear();
	_vecTargetSetItems.clear();
	for (auto ptr: _vecSetItems)
	{
		delete ptr;
	}
	_vecSetItems.clear();
	_vecConnectItems.clear();
	_vecStep.clear();
	_vecDItems.clear();
	_curMPTEMP.clear();
	_curTB;
	_curStep = 0;
	_curInitialTemperature = 0;
	_cmMap.clear();
	_currentSet.clear();
	_localValue.clear();
	ifEleToSet = false;
	_elementToSet.clear();
	_elemAnsysIdToSetid.clear();
	ifBuildMap = false;
	_nodeToElement.clear();
	allTargetEt.clear();
	allContactEt.clear();
	_mulSet.clear();

	
	if (_instance)
	{
		//delete _instance;
		_instance = nullptr;
	}


}

bool CDBReader::allocMem()
{
	// allocate all Node memory here in future.
	// rehash on scan result
	return true;
}

bool CDBReader::Scan()
{
	if (!_file->is_open())
	{
		//FDEBUG("Error: open cdb file error");
		return false;
	}

	_file->seekg(0, TxtMemStream::PosBegin);
	_nLine = _file->nLine;
	ReaderBase::InBlockTag inBlock = ReaderBase::IN_NONE;
	ANSYS_KEYWORD AsKey = KEY_UNKNOWN;

	std::string lineBuffer;
	//std::cerr << "nLine:" << _file->nLine << std::endl;
	while (_file->getline(lineBuffer))
	{
		_nLine = _file->nLine;
		if (lineBuffer.empty())
			continue;
		string lineView = lineBuffer;
		if (stringStartWith(lineBuffer, '!')
			|| stringStartWith(lineBuffer, '/'))
		{
			continue;
		}
		string strKey(std::move(splitKey(lineBuffer)));
		if (strKey.size() < 1) continue;
		toUpper(strKey);
		ANSYS_KEYWORD tmpKey = GetKey(strKey);
		if (inBlock == ReaderBase::IN_NONE)
		{
			AsKey = tmpKey;
			if (AsKey == KEY_UNKNOWN)
				continue;
		}
		else
		{
			if (tmpKey != KEY_UNKNOWN)
			{
				AsKey = tmpKey;
				inBlock = ReaderBase::IN_NONE;
			}
		}

		if (AsKey == KEY_SET)
		{
			Scan_Variable(lineBuffer);
			continue;
		}
		else
		{
			ReaderBase* pReader = GetReader(AsKey);
			if (pReader) {
				pReader->Scan(lineBuffer);
				inBlock = pReader->InBlock();
			}
		}
	}

	return true;
}

bool CDBReader::Read()
{
	if (!_file->is_open())
	{
		//FDEBUG("Error: open cdb file error");
		return false;
	}

	ReaderMgr::Inst()->AddKeyWordSupport("KEYOP", "KEYO");
	ReaderMgr::Inst()->AddKeyWordSupport("KEYOPT", "KEYO");
	ReaderMgr::Inst()->AddKeyWordSupport("NSUBST", "NSUB");
	ReaderMgr::Inst()->AddKeyWordSupport("TAXIS", "DIM");

	_file->seekg(0, TxtMemStream::PosBegin);
	_nLine = _file->nLine;
	ReaderBase::InBlockTag inBlock = ReaderBase::IN_NONE;
	ANSYS_KEYWORD AsKey = KEY_UNKNOWN;

	std::vector<std::string> tempValueString;
	std::string lineBuffer;
	while (_file->getline(lineBuffer))
	{		
		_nLine = _file->nLine;
		if (lineBuffer.empty())
			continue;
		string lineView = lineBuffer;
		if (stringStartWith(lineBuffer, '!')
			|| stringStartWith(lineBuffer, '/'))
		{
			continue;
		}

		size_t pos = lineBuffer.find_first_of("!");
		if (pos != std::string::npos)
		{
			lineBuffer.erase(lineBuffer.begin() + pos, lineBuffer.end());
		}

		pos = lineBuffer.find_last_of('\r');
		if (pos != std::string::npos)
		{
			lineBuffer.erase(pos);
		}

		pos = lineBuffer.find_last_of('\t');
		if (pos != std::string::npos)
		{
			lineBuffer.erase(pos);
		}

		string strKey(std::move(splitKey(lineBuffer)));
		if (strKey.size() < 1) continue;
		toUpper(strKey);
		Trim(strKey);
		ANSYS_KEYWORD tmpKey = GetKey(strKey);
		if (inBlock == ReaderBase::IN_NONE)
		{
			AsKey = tmpKey;
			if (AsKey == KEY_UNKNOWN)
			{
				splitView(lineBuffer, tempValueString, "=", true, true);
				if (tempValueString.size() == 2)
				{
					_localValue[tempValueString[0]] = tempValueString[1];
					tempValueString.clear();
				}
				else
				{
					tempValueString.clear();
					//Reporter::Inst()->addUnsupportedCard({ _nLine, strKey });					
				}
				continue;
			}
		}
		else
		{
			if (tmpKey != KEY_UNKNOWN)
			{
				AsKey = tmpKey;
				inBlock = ReaderBase::IN_NONE;
			}
		}

		if (AsKey == KEY_SET)
		{
			continue;
		}
		else
		{
			ReaderBase* pReader = GetReader(AsKey);
			if (pReader) {
				if (!pReader->Read(lineBuffer))
				{
					//Reporter::Inst()->addUnsupportedCard({ _nLine, strKey });
				}				
				inBlock = pReader->InBlock();
			}
		}
	}
	/*ReaderBase* pReader = GetReader(KEY_MPDATA);
	if (pReader)
	{
		bool test = pReader->clear_map();
	}*/
	return true;
}

bool CDBReader::Build()
{
	return ReaderMgr::Inst()->Build();
}

bool CDBReader::destroy_build()
{
	return ReaderMgr::Inst()->destroy_data();
}

ANSYS_KEYWORD CDBReader::GetKey(std::string& keystr)
{
	return ReaderMgr::Inst()->KeyType(keystr);
}

ReaderBase* CDBReader::GetReader(ANSYS_KEYWORD keyw)
{
	return ReaderMgr::Inst()->GetReader(keyw);
}

void CDBReader::Scan_Variable(string& strLine)
{
	std::string command, str1, str2;
	std::istringstream iss(strLine);
	std::vector<std::string> data;
	split(strLine, data, ",", true);
	if (data.size() >= 3 && data[0] == "*SET") {
		_variables[data[1]] = data[2];
	}
}

bool CDBReader::FindVariable(const std::string& str, std::string& strVal)
{
	auto findIter = _variables[str];
	if (_variables.find(str) == _variables.end())
	{
		strVal.clear();
		return true;
	}
	else
	{
		strVal = findIter;
		return true;
	}
}

AnsysET* CDBReader::FindETById(int id)
{
	if (_etMap.find(id) != _etMap.end())
		return _etVec[_etMap[id]];
	return nullptr;
}

//std::vector<MaterialBase*>* CDBReader::FindMatByID(int mid) {
//	if (_matMap.find(mid) != _matMap.end())
//		return &_matMap[mid];
//	return nullptr;
//}

bool CDBReader::FindDim(std::string& str, AnsysDim& findDim)
{
	auto iter = _dimMap.find(str);
	if (iter == _dimMap.end())
		return false;
	else
	{
		findDim = iter->second;
		return true;
	}
}

int CDBReader::AddET(AnsysET* pA)
{
	_etMap[pA->eid] = _etVec.size();
	_etVec.push_back(pA);
	if (pA->eType == 174)
	{
		allContactEt[pA->eid] = std::make_shared<Ansys_Contact174>(pA->eid);
		allContactEt[pA->eid].get()->type = ANSYS_CONTACY_TYPE::CONTA174;
	}
	else if (pA->eType == 170)
	{
		allTargetEt[pA->eid] = Ansys_Target170(pA->eid);
	}
	else if (pA->eType == 175)
	{
		allContactEt[pA->eid] = std::make_shared<Ansys_Contact175>(pA->eid);
		allContactEt[pA->eid].get()->type = ANSYS_CONTACY_TYPE::CONTA175;
	}
	return (int)_etMap.size();
}

int CDBReader::AddNode(int id, AnsysNode* pA)
{
	_nodeHlp.push_back(id);
	_nodeMap[id] = pA;
	pA->id = _nodeMap.size();
	return (int)_nodeMap.size();
}

//void CDBReader::AddElem(AnsysPropTup& prop, AnsysElem& elem)
//{
//	auto it = _propMap.find(prop);
//	if (it == _propMap.end()) {
//		_elemHlp.push_back({ elem.oldId, prop });
//		_elemHlpMap[elem.oldId] = prop;
//		_elemIdxHlpMap[elem.oldId] = _elemHlp.size() - 1;
//		_propMap[prop] = { { elem.id, elem } };
//	}
//	else
//	{
//		if (it->second.size() > 10000)
//		{
//			if (it->second.load_factor() < 1.)
//				it->second.max_load_factor(1.75);
//			if (1.74 < it->second.size() / float(it->second.bucket_count()))
//				it->second.rehash(it->second.size() * 2.5);
//		}
//		_elemHlp.push_back({ elem.oldId, prop });
//		_elemHlpMap[elem.oldId] = prop;
//		_elemIdxHlpMap[elem.oldId] = _elemHlp.size() - 1;
//		it->second[elem.id] = elem;
//	}
//}

void CDBReader::AddElement(AnsysElement& elem)
{
	checkElementNode(elem);
	_elementOut.push_back(elem);
	int elemAnsID = elem.ansysID;
	int elemOutId = _elementOut.size();
	_elemAnsysIdToOutid[elemAnsID] = elemOutId;

	AnsysPropTup prop = std::make_tuple(elem.matNum, elem.elementType, elem.realConstantNum, elem.sectinId);
	auto it = _propMap.find(prop);
	if (it == _propMap.end())
	{
		_propMap[prop] = std::vector<int>{ elemAnsID };
	}
	else
	{
		it->second.push_back(elemAnsID);
	}
}

void CDBReader::AddElementToset(AnsysElement& elem)
{
	_elementToSet.push_back(elem);
	int elemAnsID = elem.ansysID;
	int elemOutId = _elementToSet.size();
	_elemAnsysIdToSetid[elemAnsID] = elemOutId;

	AnsysPropTup prop = std::make_tuple(elem.matNum, elem.elementType, elem.realConstantNum, elem.sectinId);
	auto it = _propMap.find(prop);
	if (it == _propMap.end())
	{
		_propMap[prop] = std::vector<int>{ elemAnsID };
	}
	else
	{
		it->second.push_back(elemAnsID);
	}
}

//int CDBReader::AddMaterial(int mid, std::vector<MaterialBase*>*& pMat)
//{
//	pMat = FindMatByID(mid);
//	if (!pMat)
//	{
//		_matMap[mid] = {};
//		pMat = FindMatByID(mid);
//		if (!pMat) return -1;
//	}
//	return (int)_matMap.size();
//}

//void CDBReader::buildNodeToElement()
//{
//	if (ifBuildMap)
//	{
//		return;
//	}
//	_nodeToElement.reserve(_nodeHlp.size());
//	for (size_t i = 0; i < _elementOut.size(); i++)
//	{
//		std::vector<int>& nodes = _elementOut[i].nodeIds;
//		for (size_t j = 0; j < nodes.size(); j++)
//		{
//			_nodeToElement[nodes[j]].insert(_elementOut[i].ansysID);
//		}
//	}
//	ifBuildMap = true;
//}

//! 构架map node => {element}
void CDBReader::buildNodeToElement()
{
	if (ifBuildMap)
	{
		return;
	}
	_nodeToElement.reserve(_nodeMap.size());
	int cellCount = ReadMesh::GetCellCount();
	std::vector<int>& cellNodes = ReadMesh::GetCellNode();
	std::vector<int>& cellIndex = ReadMesh::GetCellIndex();
	if (cellIndex.size() == cellCount)
	{
		cellIndex.push_back(cellNodes.size());
	}
	for (size_t i = 0; i < cellCount; i++)
	{
		int nodeCount = cellIndex[i + 1] - cellIndex[i];
		for (size_t j = 0; j < nodeCount; j++)
		{
			_nodeToElement[cellNodes[cellIndex[i] + j]].insert(i + 1);
		}
	}
	ifBuildMap = true;
}

void CDBReader::checkElementNode(const AnsysElement& element)
{
	std::unordered_map<int, AnsysNode*>::iterator iterNode;
	for (const auto& iter : element.nodeIds)
	{
		iterNode = _nodeMap.find(iter);
		if (iterNode == _nodeMap.end())
		{
			//throw ReporterFatal<std::string>("Error node id: " + std::to_string(iter) + " in element " + std::to_string(element.ansysID) + ".");
		}
	}
}

int CDBReader::write_vtk_file(std::string exe_path, std::string read_file_path, std::string write_file_path)
{
	_nodeMap;
	_elementOut;
	_etVec; _etMap;
	auto setVTKCELLTYPE = [&](vtkIdType* ele_index, std::vector<int>& _index)
	{
		for (size_t i = 0; i < _index.size(); i++)
		{
			ele_index[i] = static_cast<VTKCellType>(_index[i]);
		}
	};

#if 0
	E_001,
		E_103,
		E_209,
		E_305,
		E_312,
		E_313,
		E_318,
		E_324,
		E_327,
#endif
	std::map<SimElem::Type, VTKCellType> _to_vtk_type =
	{
		std::make_pair(E_001, VTK_VERTEX),
		std::make_pair(E_102, VTK_LINE),
		std::make_pair(E_203, VTK_TRIANGLE),
		std::make_pair(E_204, VTK_QUAD),
		std::make_pair(E_206, VTK_QUADRATIC_TRIANGLE),
		std::make_pair(E_208, VTK_QUADRATIC_QUAD),
		std::make_pair(E_304, VTK_TETRA),
		std::make_pair(E_306, VTK_WEDGE),
		std::make_pair(E_308, VTK_HEXAHEDRON),
		std::make_pair(E_310, VTK_QUADRATIC_TETRA),
		std::make_pair(E_315, VTK_QUADRATIC_WEDGE),
		std::make_pair(E_320, VTK_QUADRATIC_HEXAHEDRON),
	};

#if 1
	std::vector<double> allNodeCoor; allNodeCoor.resize(_nodeMap.size()*3);
	for (auto&i: _nodeMap)
	{
		allNodeCoor[(i.second->id-1)*3+0] = i.second->vPos[0];
		allNodeCoor[(i.second->id-1)*3+1] = i.second->vPos[1];
		allNodeCoor[(i.second->id-1)*3+2] = i.second->vPos[2];
	}


	vtkNew<vtkPoints> all_points;
	for (int i = 0; i < allNodeCoor.size(); i += 3)
	{
		all_points->InsertNextPoint(allNodeCoor[i], allNodeCoor[i + 1], allNodeCoor[i + 2]);
	}
	vtkNew<vtkUnstructuredGrid> Grid;
	Grid->SetPoints(all_points);
	for (int i = 0; i < _elementOut.size(); i++)
	{
		auto ele_type = GetSimElemShape(_etVec[_etMap[_elementOut[i].elementType]]->eType, _elementOut[i].nodesNumInEle, _elementOut[i].nodeIds, _elementOut[i].elementType);
		VTKCellType cell_type = _to_vtk_type[ele_type];
		vector<int> ele_nodes = _elementOut[i].nodeIds;
		for (auto& j : ele_nodes)
		{
			j = _nodeMap[j]->id-1;
		}
		vtkIdType* ele_index = new vtkIdType[ele_nodes.size()];
		setVTKCELLTYPE(ele_index, ele_nodes);
		Grid->InsertNextCell(cell_type, ele_nodes.size(), ele_index);

	}
	vtkNew<vtkXMLUnstructuredGridWriter> writer;
	writer->SetInputData(Grid);
	auto pos = read_file_path.find_last_of('/');
	auto pos2 = read_file_path.find_last_of('.');
	string file_name = read_file_path.substr(pos + 1, pos2 - pos - 1);
	writer->SetFileName((write_file_path + "/" + file_name + ".vtu").c_str());
	writer->Write();
#endif
	return 0;
}

int CDBReader::write_gmsh_file_from_vtk(std::string exe_path, std::string read_file_path, std::string write_file_path)
{
	// string sys_path_str = exe_path;	sys_path_str+=":";
	// sys_path_str+=(exe_path+"/lib:");
	// sys_path_str+=(exe_path+"/lib/python3.12/site-packages:");
	// sys_path_str+=(exe_path+"/lib/python3.12/lib-dynload:");
	// sys_path_str+=(exe_path+"/lib/python3.12");
	// wchar_t* test = char_to_wchar(sys_path_str.c_str());
	//
	// Py_SetPath(test);
	Py_Initialize();
	PyRun_SimpleString("import sys;");
	PyObject* sys = PyImport_ImportModule("sys");
	PyObject* path = PyObject_GetAttrString(sys, "path");
	string py_file_path = exe_path;
	PyList_Append(path, PyUnicode_FromString(py_file_path.c_str()));

	PyObject* pModule = PyImport_ImportModule("WriteBDF");
	if (!pModule)
	{
		std::cout << "something wrong!\n";
		return -1;
	}
	PyObject* function = PyObject_GetAttrString(pModule, "write_gmsh_from_vtk");
	if (!function || !PyCallable_Check(function))
	{
		PyErr_Print();
		std::cout << "something wrong!\n";
		return -1;
	}

	string file_name = read_file_path.substr(read_file_path.find_last_of("/") + 1);
	string file_name_without_suffix = file_name.substr(0, file_name.find_last_of("."));
	PyObject* vtk_path_py = PyUnicode_FromString((write_file_path + "/" + file_name_without_suffix + ".vtu").c_str());
	PyObject* write_file_path_py = PyUnicode_FromString((write_file_path + "/" + file_name_without_suffix + ".msh").c_str());
	PyObject* res = PyObject_CallObject(function, PyTuple_Pack(2, vtk_path_py, write_file_path_py));
	Py_Finalize();
	return 0;
}

int CDBReader::AddSection(int mid, AnsysSection* sec)
{
	AnsysSection* newSection = new AnsysSection;
	newSection = sec;
	_secMap[mid] = newSection;
	return (int)_secMap.size();
}

inline bool BadId(int ndIdx, int* nids)
{
	if (nids[ndIdx] == 0)
		return true;
	for (int iNdIdx = 0; iNdIdx < ndIdx; iNdIdx++)
	{
		if (nids[ndIdx] == nids[iNdIdx])
			return true;
	}
	return false;
}

inline bool BadId(SKey ndIdx, SKey* nids)
{
	if (nids[ndIdx] == 0)
		return true;
	for (int iNdIdx = 0; iNdIdx < ndIdx; iNdIdx++)
	{
		if (nids[ndIdx] == nids[iNdIdx])
			return true;
	}
	return false;
}

static int* degenOrder(int usAnsType, int etype)
{
	AnsysElementDegenerateInfo& anaShape = _gAnsysCdbDegenOrder[_gAnsysToIBEElem[usAnsType].type];
	if (anaShape.to0.etype == etype) {
		return anaShape.to0.AnsDegenOrder;
	}
	else if (anaShape.to1.etype == etype) {
		return anaShape.to1.AnsDegenOrder;
	}
	else if (anaShape.to2.etype == etype) {
		return anaShape.to2.AnsDegenOrder;
	}
	else if (anaShape.to3.etype == etype) {
		return anaShape.to3.AnsDegenOrder;
	}
	else if (anaShape.to4.etype == etype) {
		return anaShape.to4.AnsDegenOrder;
	}
	else if (anaShape.to5.etype == etype) {
		return anaShape.to5.AnsDegenOrder;
	}
	else if (anaShape.to6.etype == etype) {
		return anaShape.to6.AnsDegenOrder;
	}
	else if (anaShape.to7.etype == etype) {
		return anaShape.to7.AnsDegenOrder;
	}
	else if (anaShape.to8.etype == etype) {
		return anaShape.to8.AnsDegenOrder;
	}
	else if (anaShape.to9.etype == etype) {
		return anaShape.to9.AnsDegenOrder;
	}
	return _gAnsysCdbDegenOrder[0].to0.AnsDegenOrder;
}

SimElem::Type GetSimElemShape(AnsElemType::Type ansEType, int& nnode, std::vector<int>& nids, int ntype)
{
	SimElem::Type SimEType = _gAnsysToIBEElem[ansEType].type;
	int nodeCntMax = _gAnsysETI[ansEType].iNodeCnt;
	if (nodeCntMax <= 0)
	{
		nnode = 0;
		return SimElem::E_UNKNOWN;
	}

	nnode = SimElemNdCnt(_gTypeIndex[SimEType]);
	switch (ansEType)
	{
	case AnsElemType::MESH200:
	{
		if (0 == ntype || 2 == ntype)
			SimEType = SimElem::E_102;
		else if (1 == ntype || 3 == ntype)
			SimEType = SimElem::E_103;
		else if (4 == ntype)
			SimEType = SimElem::E_203;
		else if (5 == ntype)
			SimEType = SimElem::E_206;
		else if (6 == ntype)
			SimEType = SimElem::E_204;
		else if (7 == ntype)
			SimEType = SimElem::E_208;
		else if (8 == ntype)
			SimEType = SimElem::E_204;
		else if (9 == ntype)
			SimEType = SimElem::E_310;
		else if (10 == ntype)
			SimEType = SimElem::E_308;
		else if (11 == ntype)
			SimEType = SimElem::E_320;
		else
			break;
		nnode = SimElemNdCnt(_gTypeIndex[SimEType]);
		break;
	}
	// QUAD4 
	case AnsElemType::PLANE13:
	case AnsElemType::PLANE25:
	case AnsElemType::FLUID29:
	case AnsElemType::INFIN47:
	case AnsElemType::PLANE55:
	case AnsElemType::SHELL63:
	case AnsElemType::PLANE75:
	case AnsElemType::FLUID130:
	case AnsElemType::FLUID136:
	case AnsElemType::PLANE182:
	case AnsElemType::CPT212:
	case AnsElemType::CPT213:
	case AnsElemType::SURF252:
	case AnsElemType::PLANE292:
		if (BadId(3, nids.data()))
		{	// TRI3
			SimEType = SimElem::E_203;
			nnode = SimElemNdCnt(_gTypeIndex[SimEType]);
			int nids_[ANSCDB_MAX_ND];
			memcpy(nids_, nids.data(), nodeCntMax * sizeof(int));
			int* od = degenOrder(ansEType, SimEType);
			nids.resize(nnode);
			for (int inode = 0; inode < nnode; inode++)
				nids[inode] = nids_[od[inode]];
		}
		break;
		// QUAD8
	case AnsElemType::PLANE77:
	case AnsElemType::PLANE78:
	case AnsElemType::PLANE83:
	case AnsElemType::PLANE121:
	case AnsElemType::CONTA174:
	case AnsElemType::PLANE183:
	case AnsElemType::PLANE223:
	case AnsElemType::PLANE230:
	case AnsElemType::PLANE233:
	case AnsElemType::PLANE238:
	case AnsElemType::PLANE293:
		if (BadId(3, nids.data()) && BadId(6, nids.data()))
		{	//  TRI6
			SimEType = SimElem::E_206;
			nnode = SimElemNdCnt(_gTypeIndex[SimEType]);
			int nids_[ANSCDB_MAX_ND];
			memcpy(nids_, nids.data(), nodeCntMax * sizeof(int));
			int* od = degenOrder(ansEType, SimEType);
			nids.resize(nnode);
			for (int inode = 0; inode < nnode; inode++)
				nids[inode] = nids_[od[inode]];
		}
		break;
	case AnsElemType::TARGET170:
		if (BadId(3, nids.data()) && BadId(6, nids.data()))
		{	//  TRI6
			SimEType = SimElem::E_206;
			nnode = SimElemNdCnt(_gTypeIndex[SimEType]);
			int nids_[ANSCDB_MAX_ND];
			memcpy(nids_, nids.data(), nodeCntMax * sizeof(int));
			int* od = degenOrder(ansEType, SimEType);
			nids.resize(nnode);
			for (int inode = 0; inode < nnode; inode++)
				nids[inode] = nids_[od[inode]];
		}
		else if (BadId(3, nids.data()))
		{	//  TRI3
			SimEType = SimElem::E_203;
			nnode = SimElemNdCnt(_gTypeIndex[SimEType]);
			int nids_[ANSCDB_MAX_ND];
			memcpy(nids_, nids.data(), nodeCntMax * sizeof(int));
			int* od = degenOrder(ansEType, SimEType);
			nids.resize(nnode);
			for (int inode = 0; inode < nnode; inode++)
				nids[inode] = nids_[od[inode]];
		}
		else
		{	//  Point
			SimEType = SimElem::E_001;
			nnode = SimElemNdCnt(_gTypeIndex[SimEType]);
			int nids_[ANSCDB_MAX_ND];
			memcpy(nids_, nids.data(), nodeCntMax * sizeof(int));
			int* od = degenOrder(ansEType, SimEType);
			nids.resize(nnode);
			for (int inode = 0; inode < nnode; inode++)
				nids[inode] = nids_[od[inode]];
		}
		break;
		// HEX8
	case AnsElemType::SOLID5:
		if (BadId(3, nids.data()) && BadId(7, nids.data()))
		{	// Prism6
			SimEType = SimElem::E_306;
			nnode = SimElemNdCnt(_gTypeIndex[SimEType]);
			int nids_[ANSCDB_MAX_ND];
			memcpy(nids_, nids.data(), nodeCntMax * sizeof(int));
			int* od = degenOrder(ansEType, SimEType);
			nids.resize(nnode);
			for (int inode = 0; inode < nnode; inode++)
				nids[inode] = nids_[od[inode]];
		}
		break;
		// HEX8
	case AnsElemType::FLUID30:
	case AnsElemType::SOLID70:
	case AnsElemType::SOLID96:
	case AnsElemType::SOLID185:
	case AnsElemType::CPT215:
	case AnsElemType::SOLID225:
		//case AnsElemType::INFIN257:
		if (BadId(3, nids.data()) &&
			BadId(5, nids.data()) && BadId(6, nids.data()) && BadId(7, nids.data()))	    // A,B
		{	// Tet4
			SimEType = SimElem::E_304;
			nnode = SimElemNdCnt(_gTypeIndex[SimEType]);
			int nids_[ANSCDB_MAX_ND];
			memcpy(nids_, nids.data(), nodeCntMax * sizeof(int));
			int* od = degenOrder(ansEType, SimEType);
			nids.resize(nnode);
			for (int inode = 0; inode < nnode; inode++)
				nids[inode] = nids_[od[inode]];
		}
		else if (BadId(5, nids.data()) && BadId(6, nids.data()) && BadId(7, nids.data()))
		{	// Pyramid
			SimEType = SimElem::E_305;
			nnode = SimElemNdCnt(_gTypeIndex[SimEType]);
			int nids_[ANSCDB_MAX_ND];
			memcpy(nids_, nids.data(), nodeCntMax * sizeof(int));
			int* od = degenOrder(ansEType, SimEType);
			nids.resize(nnode);
			for (int inode = 0; inode < nnode; inode++)
				nids[inode] = nids_[od[inode]];
		}
		else if (BadId(3, nids.data()) && BadId(7, nids.data()))
		{	// Prism
			SimEType = SimElem::E_306;
			nnode = SimElemNdCnt(_gTypeIndex[SimEType]);
			int nids_[ANSCDB_MAX_ND];
			memcpy(nids_, nids.data(), nodeCntMax * sizeof(int));
			int* od = degenOrder(ansEType, SimEType);
			nids.resize(nnode);
			for (int inode = 0; inode < nnode; inode++)
				nids[inode] = nids_[od[inode]];
		}
		break;
		// HEX20
	case AnsElemType::SOLID90:
	case AnsElemType::INFIN111:
	case AnsElemType::SOLID122:
	case AnsElemType::SOLID186:
	case AnsElemType::CPT216:
	case AnsElemType::FLUID220:
	case AnsElemType::SOLID226:
	case AnsElemType::SOLID231:
	case AnsElemType::SOLID236:
	case AnsElemType::SOLID239:
		if (BadId(3, nids.data()) && BadId(10, nids.data()) &&	                // K,L,S
			BadId(5, nids.data()) && BadId(6, nids.data()) && BadId(7, nids.data()) &&	// M,N,O,P,U,V,W,X
			BadId(13, nids.data()) && BadId(14, nids.data()) && BadId(15, nids.data()) &&
			BadId(19, nids.data()))	                                    // A,B
		{	// Tet10
			SimEType = SimElem::E_310;
			nnode = SimElemNdCnt(_gTypeIndex[SimEType]);
			int nids_[ANSCDB_MAX_ND];
			memcpy(nids_, nids.data(), nodeCntMax * sizeof(int));
			int* od = degenOrder(ansEType, SimEType);
			nids.resize(nnode);
			for (int inode = 0; inode < nnode; inode++)
				nids[inode] = nids_[od[inode]];
		}
		else if (BadId(5, nids.data()) && BadId(6, nids.data()) && BadId(7, nids.data()) &&	// M,N,O,P,U,V,W,X
			BadId(13, nids.data()) && BadId(14, nids.data()) && BadId(15, nids.data()))
		{	// Pyramid
			SimEType = SimElem::E_313;
			nnode = SimElemNdCnt(_gTypeIndex[SimEType]);
			int nids_[ANSCDB_MAX_ND];
			memcpy(nids_, nids.data(), nodeCntMax * sizeof(int));
			int* od = degenOrder(ansEType, SimEType);
			nids.resize(nnode);
			for (int inode = 0; inode < nnode; inode++)
				nids[inode] = nids_[od[inode]];
		}
		else if (BadId(3, nids.data()) && BadId(10, nids.data()) &&	        	// K,L,S
			BadId(7, nids.data()) && BadId(14, nids.data()) &&		            // O,P,W
			BadId(19, nids.data())							                // A,B
			)
		{	// Prism
			SimEType = SimElem::E_315;
			nnode = SimElemNdCnt(_gTypeIndex[SimEType]);
			int nids_[ANSCDB_MAX_ND];
			memcpy(nids_, nids.data(), nodeCntMax * sizeof(int));
			int* od = degenOrder(ansEType, SimEType);
			nids.resize(nnode);
			for (int inode = 0; inode < nnode; inode++)
				nids[inode] = nids_[od[inode]];
		}
		break;
	default:
		break;
	}

	for (size_t iNd = _gAnsysETI[ansEType].iNodeCornerCnt; iNd < nnode && iNd < _gAnsysETI[ansEType].iNodeCnt; iNd++)
	{
		if (nids[iNd] == 0) {
			SimEType = _gTypeSimple[SimEType];
			nnode = SimElemNdCnt(_gTypeIndex[SimEType]);
			break;
		}
	}
	for (size_t iNd = 0; iNd < nnode && iNd < nodeCntMax; iNd++)
	{
		if (nids[iNd] == 0) {
			SimEType = SimElem::E_UNKNOWN;
			nnode = SimElemNdCnt(_gTypeIndex[SimEType]);
			break;
		}
	}
	return SimEType;
}